﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace xunsearch.lib
{
    interface XSTokenizer
    {
        ///// <summary>
        ///// 内置分词器定义(常量)
        ///// </summary>
        //public const int DEL = 0;

        /// <summary>
        /// 执行分词并返回词列表
        /// </summary>
        /// <param name="value">待分词的字段值(UTF-8编码)</param>
        /// <param name="doc">当前相关的索引文档</param>
        /// <returns>切好的词组成的数组</returns>
        List<string> getTokens(string value, XSDocument doc = null);
    }

    /// <summary>
    /// 内置空分词器
    /// </summary>
    public class XSTokenizerNone : XSTokenizer 
    {
        public List<string> getTokens(string value, XSDocument doc) 
        {
            return new List<string>();
        }
    }

    /// <summary>
    /// 内置整值分词器
    /// </summary>
    public class XSTokenizerFull : XSTokenizer
    {
        public List<string> getTokens(string value, XSDocument doc) 
        {
            List<string> list = new List<string>();
            list.Add(value);
            return list;
        }
    }

    /// <summary>
    /// 内置的分割分词器
    /// </summary>
    public class XSTokenizerSplit : XSTokenizer
    {
        private string arg = " ";

        public XSTokenizerSplit(string _arg = "") 
        {
            if (_arg != null && _arg != "") 
            {
                arg = _arg;
            }
        }

        public List<string> getTokens(string value, XSDocument doc = null) 
        {
            if (arg.Length > 2 && arg.Substring(0, 1) == "/" && arg.Substring(arg.Length - 1, 1) == "/") 
            {
                //正则
                return Tool.preg_match_all(arg, value);
            }
            return Tool.explode(arg, value);
        }

       
    }

    /// <summary>
    /// 内置的定长分词器
    /// </summary>
    public class XSTokenizerXlen : XSTokenizer 
    {
        private int arg = 2;

        public XSTokenizerXlen(string _arg = "") 
        {
            if (_arg != null && _arg != "") 
            {
                arg = int.Parse(_arg);
                if (arg < 1 || arg > 255) 
                {
                    throw new Exception("Invalid argument for XSTokenizerXlen : " + _arg);
                }
            }
        }

        public List<string> getTokens(string value, XSDocument doc = null) 
        {
            List<string> terms = new List<string>();
            for (int i = 0; i < value.Length; i += arg) 
            {
                terms.Add(value.Substring(i, arg));
            }
            return terms;
        }
    }

    /// <summary>
    /// 内置的步长分词器
    /// </summary>
    public class XSTokenizerXstep : XSTokenizer
    {
        private int arg = 2;
        public XSTokenizerXstep(string _arg = "") 
        {
            if (_arg != null && _arg != "") 
            {
                arg = int.Parse(_arg);
                if (arg < 1 && arg > 255) 
                {
                    throw new Exception("Invalid argument for XSTokenizerXstep : " + _arg);
                }
            }
        }

        public List<string> getTokens(string value, XSDocument doc = null) 
        {
            List<string> terms = new List<string>();
            int i = arg;
            while (true) 
            {
                terms.Add(value.Substring(0, i));
                if (i > value.Length) 
                {
                    break;
                }
                i += arg;
            }
            return terms;
        }
    }

    public class XSTokenizerScws : XSTokenizer 
    {
        private const int MULTI_MASK = 15;

        private const int SCWS_XDICT_XDB = 1;
        private const int SCWS_XDICT_MEM = 2;
        private const int SCWS_XDICT_TXT = 4;

        private const int SCWS_MULTI_NONE = 0;
        private const int SCWS_MULTI_SHORT = 1;
        private const int SCWS_MULTI_DUALITY = 2;
        private const int SCWS_MULTI_ZMAIN = 4;
        private const int SCWS_MULTI_ZALL = 8;
        /// <summary>
        /// 字符集，默认为项目字符集
        /// </summary>
        private static string _charset;

        /// <summary>
        /// 选项设置记录
        /// </summary>
        private Dictionary<string, XSCommand> _setting = new Dictionary<string, XSCommand>();

        /// <summary>
        /// 分词服务对象
        /// </summary>
        private static XSServer _server;

        public XSTokenizerScws(string arg = null) 
        {
            if (_server == null) 
            {
                XS xs = XS.getLastXS();
                if (xs == null) 
                {
                    throw new Exception("An XS instance should be created before using XSTokenizerScws");
                }
                _server = xs.getScwsServer();
                _server.setTimeout(0);
                _charset = xs.getDefaultCharset();
            }

            if (arg != null && arg != "") 
            {
                setMulti(int.Parse(arg));
            }
        }

        /// <summary>
        /// XSTokenizer 接口
        /// </summary>
        /// <param name="value"></param>
        /// <param name="doc"></param>
        /// <returns></returns>
        public List<string> getTokens(string value, XSDocument doc = null) 
        {
            List<string> tokens = new List<string>();
            setIgnore(true);
            //save charset, force to use UTF-8
            string charset = _charset;
            _charset = "UTF-8";
            List<Dictionary<string, string>> words = getResult(value);
            foreach (var de in words) 
            {
                tokens.Add(de["word"]);
            }
            _charset = charset;
            return tokens;
        }


        /// <summary>
        /// 设置字符集
        /// </summary>
        /// <param name="charset"></param>
        /// <returns></returns>
        public XSTokenizerScws setCharset(string charset) 
        {
            _charset = charset.ToUpper();
            if (_charset == "UTF8") 
            {
                _charset = "UTF-8";
            }
            return this;
        }

        /// <summary>
        /// 设置复合分词选项
        /// </summary>
        /// <param name="mode">mode 复合选项, 值范围 0~15
        /// 默认为值为 3, 可使用常量组合: 
        /// SCWS_MULTI_SHORT|SCWS_MULTI_DUALITY|SCWS_MULTI_ZMAIN|SCWS_MULTI_ZALL</param>
        /// <returns></returns>
        public XSTokenizerScws setMulti(int mode = 3) 
        {
            mode = mode & MULTI_MASK;
            if (_setting.ContainsKey("multi"))
            {
                _setting["multi"] = new XSCommand(xs_cmd.CMD_SEARCH_SCWS_SET, xs_cmd.CMD_SCWS_SET_MULTI, mode);
            }
            else 
            {
                _setting.Add("multi", new XSCommand(xs_cmd.CMD_SEARCH_SCWS_SET, xs_cmd.CMD_SCWS_SET_MULTI, mode));
            }
            //to-do
            return this;
        }

        /// <summary>
        /// 设置忽略标点符号
        /// </summary>
        /// <param name="yes"></param>
        /// <returns></returns>
        public XSTokenizerScws setIgnore(bool yes = true) 
        {
            if (_setting.ContainsKey("ignore"))
            {
                _setting["ignore"] = new XSCommand(xs_cmd.CMD_SEARCH_SCWS_SET, xs_cmd.CMD_SCWS_SET_IGNORE, yes == false ? 0 : 1);//to-do
            }
            else 
            {
                _setting.Add("ignore", new XSCommand(xs_cmd.CMD_SEARCH_SCWS_SET, xs_cmd.CMD_SCWS_SET_IGNORE, yes == false ? 0 : 1));
            }
            return this;
        }

        /// <summary>
        /// 设置分词词典, 支持 TXT/XDB 格式
        /// </summary>
        /// <param name="fpath">服务端的词典路径</param>
        /// <param name="mode">词典类型, 常量: SCWS_XDICT_XDB|SCWS_XDICT_TXT|SCWS_XDICT_MEM</param>
        /// <returns></returns>
        public XSTokenizerScws setDict(string fpath, int mode = 0) 
        {
            if (mode == 0) 
            {
                mode = fpath.IndexOf(".txt") < 0 ? SCWS_XDICT_TXT : SCWS_XDICT_XDB;
            }
            if (_setting.ContainsKey("set_dict"))
            {
                _setting.Add("set_dict", new XSCommand(xs_cmd.CMD_SEARCH_SCWS_SET, xs_cmd.CMD_SCWS_SET_DICT, mode, fpath));
            }
            else 
            {
                _setting["set_dict"] = new XSCommand(xs_cmd.CMD_SEARCH_SCWS_SET, xs_cmd.CMD_SCWS_SET_DICT, mode, fpath);//to-do
            }

            _setting.Remove("add_dict");
            return this;
        }

        /// <summary>
        /// 添加分词词典, 支持 TXT/XDB 格式
        /// </summary>
        /// <param name="fpath">服务端的词典路径</param>
        /// <param name="mode">词典类型, 常量: SCWS_XDICT_XDB|SCWS_XDICT_TXT|SCWS_XDICT_MEM</param>
        /// <returns>返回对象本身以支持串接操作</returns>
        public XSTokenizerScws addDict(string fpath, int mode = 0)
        {
            if (mode == 0) 
            {
                mode = fpath.IndexOf(".txt") < 0 ? SCWS_XDICT_TXT : SCWS_XDICT_XDB;
            }
            if (!_setting.ContainsKey("add_dict")) 
            {
                _setting.Add("add_dict", new XSCommand(xs_cmd.CMD_SEARCH_SCWS_SET, xs_cmd.CMD_SCWS_ADD_DICT, mode, fpath));
            }
            _setting["add_dict"] = new XSCommand(xs_cmd.CMD_SEARCH_SCWS_SET, xs_cmd.CMD_SCWS_ADD_DICT, mode, fpath);//to do array()类型混乱
            return this;
        }

        /// <summary>
        /// 设置散字二元组合
        /// </summary>
        /// <param name="yes">是否开启散字自动二分组合功能</param>
        /// <returns></returns>
        public XSTokenizerScws setDuality(bool yes = true) 
        {
            if (_setting.ContainsKey("duality"))
            {
                _setting["duality"] = new XSCommand(xs_cmd.CMD_SEARCH_SCWS_SET, xs_cmd.CMD_SCWS_SET_DUALITY, yes == false? 0 : 1);
            }
            else 
            {
                _setting.Add("duality", new XSCommand(xs_cmd.CMD_SEARCH_SCWS_SET, xs_cmd.CMD_SCWS_SET_DUALITY, yes == false ? 0 : 1));
            }
            return this;
        }

        /// <summary>
        /// 获取 scws 版本号
        /// </summary>
        /// <returns>string 版本号</returns>
        public string getVersion() 
        {
            XSCommand cmd = new XSCommand(xs_cmd.CMD_SEARCH_SCWS_GET, xs_cmd.CMD_SCWS_GET_VERSION);
            XSCommand res = _server.execCommand(cmd, xs_cmd.CMD_OK_DB_INFO);
            return res.buf1;
        }

        public List<Dictionary<string, string>> getResult(string text) 
        {
            List<Dictionary<string, string>> words = new List<Dictionary<string, string>>();
            text = "";//
            XSCommand cmd = new XSCommand(xs_cmd.CMD_SEARCH_SCWS_GET, xs_cmd.CMD_SCWS_GET_RESULT, 0, text);
            XSCommand res = _server.execCommand(cmd, xs_cmd.CMD_OK_SCWS_RESULT);
            while (res.buf1 != "") 
            {
                res = _server.getRespond();
            }
            return words;
        }
    }
}
